<script lang="ts" setup>
import '@toast-ui/editor/dist/toastui-editor.css';
import '@toast-ui/editor/dist/theme/toastui-editor-dark.css';

import Editor from '@toast-ui/editor';
import '@toast-ui/editor/dist/i18n/zh-cn';
import { ref, watch, onMounted, onUnmounted, type PropType } from 'vue';
import { useFormItem, Notification } from '@arco-design/web-vue';
import prettyBytes from 'pretty-bytes';
import useUploader from '@/settings/hooks/uploader';
import { useAppStore } from '@/settings/stores';
import { useI18n } from 'vue-i18n';

defineOptions({
  name: 'OpenMarkdownEditor',
});

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },

  height: {
    type: Number,
    default: 500,
  },

  maxFileSize: {
    type: Number,
    default: 1024 * 1024 * 10,
  },

  toolbar: {
    type: Array as PropType<string[][]>,
    default: () => [
      ['heading', 'bold', 'italic', 'strike'],
      ['hr', 'quote'],
      ['ul', 'ol'],
      ['link', 'image', 'table', 'code', 'codeblock'],
    ],
  },

  break: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits(['update:modelValue']);
const { locale, t } = useI18n();
const editor = ref();
let instance: Editor;
const { eventHandlers } = useFormItem();
const { uploadFile } = useUploader();
const appStore = useAppStore();
let lastUpdateContent = '';

const change = () => {
  const content = instance.getMarkdown();

  lastUpdateContent = content;

  emit('update:modelValue', content);

  eventHandlers.value?.onChange?.();
};

watch(() => props.modelValue, (value) => {
  if (value === lastUpdateContent) {
    return;
  }

  instance.setMarkdown(value, false);
});

watch(() => appStore.theme, (value) => {
  const el = editor.value.querySelector?.('.toastui-editor-defaultUI');

  if (!el) {
    return;
  }

  if (value === 'dark') {
    el?.classList?.add?.('toastui-editor-dark');
  }
  else {
    el?.classList?.remove?.('toastui-editor-dark');
  }
});

const toggleEditorFullScreen = (element: HTMLElement) => {
  if (!document.fullscreenElement) {
    element.requestFullscreen?.();
  }
  else {
    document.exitFullscreen?.();
  }
}

onMounted(() => {
  const createFullscreenButton = () => {
    const button = document.createElement('button');
    const defaultClassName = 'toastui-editor-toolbar-icons fullscreen-button';

    button.className = defaultClassName;
    button.style.backgroundImage = 'none';
    button.style.margin = '0';
    button.textContent = `F`;
    button.type = 'button';
    button.addEventListener('click', () => {
      toggleEditorFullScreen(editor.value);
    });

    return button;
  }

  instance = new Editor({
    el: editor.value,
    language: locale.value,
    initialEditType: 'markdown',
    previewStyle: 'vertical',
    usageStatistics: false,
    height: `${props.height}px`,
    hideModeSwitch: true,
    autofocus: false,
    previewHighlight: false,
    toolbarItems: [
      ...props.toolbar,
      [{
        el: createFullscreenButton(),
        name: 'fullscreen',
        tooltip: t('settings.component.markdownEditor.toolbar.fullscreen'),
      }],
      // ['scrollSync'],
    ],
    theme: appStore.theme,
    initialValue: props.modelValue,
    customHTMLRenderer: props.break ? undefined : {
      softbreak() {
        return {
          type: 'html',
          content: '\n',
        };
      },
    },
    events: {
      change,
    },
    hooks: {
      addImageBlobHook: async (file: File | Blob, cb: (url: string) => void) => {
        if (file.size > props.maxFileSize) {
          Notification.error({
            content: t('settings.notification.fileLarge', { size: prettyBytes(props.maxFileSize) }),
            duration: 10 * 1000,
          });

          return;
        }

        const { isSuccess, url, msg } = await uploadFile(file as File);

        if (!isSuccess || !url) {
          Notification.error({
            content: msg, duration: 10 * 1000,
          });

          return;
        }

        cb(url);
      },
    },
  });
});

onUnmounted(() => {
  instance.destroy();
});

defineExpose({
  scrollToTop() {
    setTimeout(() => {
      instance?.setScrollTop(0);
      instance?.moveCursorToStart(false);
    });
  },
});
</script>

<template>
  <div class="open-markdown-editor w-full" ref="editor"></div>
</template>

<style lang="scss" scoped>
.open-markdown-editor {
  :deep() {
    .toastui-editor-defaultUI {
      .toastui-editor-toolbar {
        background-color: #fff;
      }

      .toastui-editor-ok-button {
        background-color: #1180ff;
        outline-color: #1180ff;
      }

      .toastui-editor-md-container {
        background-color: #fff;
      }

      .fullscreen-button {
        color: #333;
        font-size: 16px;

        &.active {
          color: #1180ff;
        }
      }

      .toastui-editor-contents {
        font-size: 14px;

        p {
          margin-top: 1em;
          margin-bottom: 1em;
          font-size: 16px;
          line-height: 1.6;
        }

        img {
          display: block;
          margin: 0;
          object-fit: contain;
          vertical-align: baseline;
          border-style: none;
        }
      }

      .ProseMirror {
        font-size: 14px;

        div {
          font-size: 16px;
        }
      }
    }

    .toastui-editor-dark {
      &.toastui-editor-defaultUI {
        .toastui-editor-toolbar {
          background-color: #121212;
        }

        .toastui-editor-ok-button {
          background-color: #379cff;
          outline-color: #379cff;
        }

        .toastui-editor-md-container {
          background-color: #121212;
        }

        .fullscreen-button {
          color: #fff;

          &.active {
            color: #379cff;
          }
        }
      }
    }
  }
}
</style>
